# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-05 23:13
# File     : auth_routes.py
# Project  : codebuddy_craft
# Desc     : 认证API路由和其他核心代码

"""
认证API路由 🔐

处理用户登录、注册、令牌管理等认证相关功能
"""

"""
认证API路由 🔐

处理用户登录、注册、令牌管理等认证相关功能
"""

from fastapi import APIRouter, Depends, HTTPException, status, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from datetime import timedelta
from typing import Optional

from backend.database.connection import get_db
from backend.models.user import User
from backend.core.settings import get_settings  # 导入设置
from backend.utils.security import (
    verify_password, get_password_hash, create_access_token,
    create_refresh_token, verify_token, validate_password_strength,
    check_rate_limit
)
from backend.utils.logger import get_logger
from backend.utils.log_utils import log_security_event
from backend.schemas.auth import (
    LoginRequest, RegisterRequest, TokenResponse,
    RefreshTokenRequest, ChangePasswordRequest
)
from backend.schemas.user import UserResponse

router = APIRouter()
logger = get_logger(__name__)
security = HTTPBearer()
settings = get_settings()  # 获取设置实例


def get_client_ip(request: Request) -> str:
    """获取客户端IP地址"""
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        return forwarded.split(",")[0].strip()
    return request.client.host if request.client else "unknown"


async def get_current_user(
        credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
        db: AsyncSession = Depends(get_db)
) -> Optional[User]:
    """获取当前用户"""
    if not credentials:
        return None

    token_data = verify_token(credentials.credentials)
    if not token_data:
        return None

    user_id = token_data.get("sub")
    if not user_id:
        return None

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()

    if not user or not user.is_active:
        return None

    return user


async def require_auth(
        credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
        db: AsyncSession = Depends(get_db)
) -> User:
    """要求认证的依赖"""
    if not credentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="未提供认证令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )

    token_data = verify_token(credentials.credentials)
    if not token_data:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的认证令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )

    user_id = token_data.get("sub")
    if not user_id:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌中缺少用户信息",
            headers={"WWW-Authenticate": "Bearer"},
        )

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()

    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在",
            headers={"WWW-Authenticate": "Bearer"},
        )

    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户账户已被禁用",
            headers={"WWW-Authenticate": "Bearer"},
        )

    return user


@router.post("/register", response_model=TokenResponse, status_code=status.HTTP_201_CREATED)
async def register(
        user_data: RegisterRequest,
        request: Request,
        db: AsyncSession = Depends(get_db)
):
    """用户注册 📝"""

    # 速率限制检查
    if settings.RATE_LIMIT_ENABLED:
        await check_rate_limit(
            request.client.host,
            "register",
            settings.REGISTER_RATE_LIMIT
        )

    # 验证密码强度
    password_check = validate_password_strength(user_data.password)
    if not password_check['is_valid']:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail={"message": "密码强度不足", "errors": password_check['errors']}
        )

    # 检查用户名是否已存在
    result = await db.execute(select(User).where(User.username == user_data.username))
    if result.scalar_one_or_none():
        log_security_event("DUPLICATE_USERNAME", ip_address=client_ip, details={"username": user_data.username})
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户名已存在"
        )

    # 检查邮箱是否已存在
    result = await db.execute(select(User).where(User.email == user_data.email))
    if result.scalar_one_or_none():
        log_security_event("DUPLICATE_EMAIL", ip_address=client_ip, details={"email": user_data.email})
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="邮箱已被注册"
        )

    # 创建新用户
    hashed_password = get_password_hash(user_data.password)
    new_user = User(
        username=user_data.username,
        email=user_data.email,
        full_name=user_data.full_name,
        hashed_password=hashed_password,
        is_verified=not settings.ENABLE_EMAIL_VERIFICATION
    )

    db.add(new_user)
    await db.commit()
    await db.refresh(new_user)

    logger.success(f"新用户注册成功: {new_user.username}")
    log_security_event("USER_REGISTERED", user_id=new_user.id, ip_address=client_ip)

    return UserResponse.from_orm(new_user)


@router.post("/login", response_model=TokenResponse)
async def login(
        request: Request,
        login_data: LoginRequest,
        db: AsyncSession = Depends(get_db)
):
    """用户登录 🔑"""
    client_ip = get_client_ip(request)

    # 速率限制检查
    if not check_rate_limit(f"login:{client_ip}", max_requests=10, window_seconds=900):
        log_security_event("RATE_LIMIT_EXCEEDED", ip_address=client_ip, details={"action": "login"})
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="登录尝试过于频繁，请稍后再试"
        )

    # 查找用户
    result = await db.execute(
        select(User).where(
            (User.username == login_data.username) |
            (User.email == login_data.username)
        )
    )
    user = result.scalar_one_or_none()

    # 验证用户和密码
    if not user or not verify_password(login_data.password, user.hashed_password):
        log_security_event("LOGIN_FAILED", ip_address=client_ip, details={"username": login_data.username})
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户名或密码错误"
        )

    if not user.is_active:
        log_security_event("LOGIN_INACTIVE_USER", user_id=user.id, ip_address=client_ip)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="账户已被禁用"
        )

    # 创建令牌
    access_token = create_access_token({"sub": user.id, "username": user.username})
    refresh_token = create_refresh_token({"sub": user.id})

    # 更新最后登录时间
    from sqlalchemy import func
    user.last_login_at = func.now()
    await db.commit()

    logger.success(f"用户登录成功: {user.username}")
    log_security_event("LOGIN_SUCCESS", user_id=user.id, ip_address=client_ip)

    return TokenResponse(
        access_token=access_token,
        refresh_token=refresh_token,
        token_type="bearer",
        expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
    )


@router.post("/refresh", response_model=TokenResponse)
async def refresh_token(
        request: Request,
        refresh_data: RefreshTokenRequest,
        db: AsyncSession = Depends(get_db)
):
    """刷新访问令牌 🔄"""
    client_ip = get_client_ip(request)

    # 验证刷新令牌
    token_data = verify_token(refresh_data.refresh_token, token_type="refresh")
    if not token_data:
        log_security_event("INVALID_REFRESH_TOKEN", ip_address=client_ip)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的刷新令牌"
        )

    user_id = token_data.get("sub")
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()

    if not user or not user.is_active:
        log_security_event("REFRESH_TOKEN_INVALID_USER", user_id=user_id, ip_address=client_ip)
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在或已被禁用"
        )

    # 生成新的访问令牌
    access_token = create_access_token({"sub": user.id, "username": user.username})

    logger.info(f"令牌刷新成功: {user.username}")

    return TokenResponse(
        access_token=access_token,
        refresh_token=refresh_data.refresh_token,  # 返回原刷新令牌
        token_type="bearer",
        expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
    )


@router.post("/change-password")
async def change_password(
        request: Request,
        password_data: ChangePasswordRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """修改密码 🔐"""
    client_ip = get_client_ip(request)

    # 验证当前密码
    if not verify_password(password_data.current_password, current_user.hashed_password):
        log_security_event("PASSWORD_CHANGE_FAILED", user_id=current_user.id, ip_address=client_ip)
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="当前密码错误"
        )

    # 验证新密码强度
    password_check = validate_password_strength(password_data.new_password)
    if not password_check['is_valid']:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail={"message": "新密码强度不足", "errors": password_check['errors']}
        )

    # 更新密码
    current_user.hashed_password = get_password_hash(password_data.new_password)
    await db.commit()

    logger.success(f"用户密码修改成功: {current_user.username}")
    log_security_event("PASSWORD_CHANGED", user_id=current_user.id, ip_address=client_ip)

    return {"message": "密码修改成功"}


@router.post("/logout")
async def logout(
        request: Request,
        current_user: User = Depends(require_auth)
):
    """用户登出 👋"""
    client_ip = get_client_ip(request)

    # 注意：由于JWT是无状态的，实际的登出需要在客户端删除令牌
    # 这里主要用于记录登出事件
    logger.info(f"用户登出: {current_user.username}")
    log_security_event("LOGOUT", user_id=current_user.id, ip_address=client_ip)

    return {"message": "登出成功"}


@router.get("/me", response_model=UserResponse)
async def get_current_user_info(current_user: User = Depends(require_auth)):
    """获取当前用户信息 👤"""
    return UserResponse.from_orm(current_user)


@router.post("/verify-token")
async def verify_user_token(
        credentials: HTTPAuthorizationCredentials = Depends(security),
        db: AsyncSession = Depends(get_db)
):
    """验证令牌有效性 ✅"""
    if not credentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="未提供认证令牌"
        )

    token_data = verify_token(credentials.credentials)
    if not token_data:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的认证令牌"
        )

    user_id = token_data.get("sub")
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()

    if not user or not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在或已被禁用"
        )

    return {
        "valid": True,
        "user_id": user.id,
        "username": user.username,
        "expires_at": token_data.get("exp")
    }
